﻿using ETModel;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace ETHotfix {
    /// <summary>
    /// 消息发送快捷操作累
    /// </summary>
    public static class MessageHelper {

        /// <summary>
        /// 发送actor消息
        /// </summary>
        /// <param name="message">ActorId需要有值</param>
        public static void SendActorMessage(this IActorMessage message) {
            var actorMsgSenderComp = Game.Scene.GetComponent<ActorMessageSenderComponent>();
            var actorMsgSender = actorMsgSenderComp.Get(message.ActorId);
            actorMsgSender.Send(message);
        }
        /// <summary>
        /// 发送actor消息
        /// </summary>
        /// <param name="request">ActorId需要有值</param>
        public static async ETTask<IActorResponse> CallActorMessage(this IActorRequest request) {
            var actorMsgSenderComp = Game.Scene.GetComponent<ActorMessageSenderComponent>();
            var actorMsgSender = actorMsgSenderComp.Get(request.ActorId);
            return await actorMsgSender.Call(request);
        }

        #region 在Gate服务器发消息

        /// <summary>
        /// 在map服务器,全服务器广播消息给客户端
        /// </summary>
        /// <param name="message"></param>
        /// <param name="excludePlayerId"></param>
        public static void GateBroadcastAllPlayers(this IMessage message, long? excludePlayerId = null) {
            if (!StartConfigComponent.Instance.StartConfig.AppType.HasFlag(AppType.Gate)) {
                Log.Error("必须在Gate服务器调用");
                return;
            }
            var players = Game.Scene.GetComponent<GatePlayersComponent>()?.GetAll();
            foreach (var player in players) {
                if ((excludePlayerId.HasValue && excludePlayerId.Value == player.Id)) {
                    continue;
                }
                var gateSession = player.Parent as Session;
                if (gateSession == null || gateSession.IsDisposed) continue;
                gateSession.Send(message);
            }
        }

        /// <summary>
        /// 在Gate服务器,给指定几个玩家广播消息
        /// </summary>
        /// <param name="message"></param>
        /// <param name="players"></param>
        public static void GateBroadcastTo(this IMessage message, IEnumerable<GatePlayer> players) {
            if (!StartConfigComponent.Instance.StartConfig.AppType.HasFlag(AppType.Gate)) {
                Log.Error("必须在Gate服务器调用");
                return;
            }
            if (players == null || players.Count() <= 0) return;
            foreach (var player in players) {
                var gateSession = player.Parent as Session;
                if (gateSession == null || gateSession.IsDisposed) continue;

                gateSession.Send(message);
            }
        }

        /// <summary>
        /// 在Gate服务器,发送消息给指定玩家
        /// </summary>
        /// <param name="message"></param>
        /// <param name="player"></param>
        public static void GateSendTo(this IMessage message, GatePlayer player) {
            if (!StartConfigComponent.Instance.StartConfig.AppType.HasFlag(AppType.Gate)) {
                Log.Error("必须在Gate服务器调用");
                return;
            }
            if (player == null) return;
            var gateSession = player.Parent as Session;
            if (gateSession == null || gateSession.IsDisposed) return;

            gateSession.Send(message);
        }
        #endregion

        #region 在Map服务器发消息

        /// <summary>
        /// 在map服务器,全服务器广播消息给客户端
        /// </summary>
        /// <param name="message"></param>
        /// <param name="excludePlayerId"></param>
        public static void MapBroadcastAllPlayers(this IActorMessage message, long? excludePlayerId = null) {
            if (!StartConfigComponent.Instance.StartConfig.AppType.HasFlag(AppType.Map)) {
                Log.Error("必须在Map服务器调用");
                return;
            }
            var players = Game.Scene.GetComponent<MapPlayersComponent>()?.GetAll();
            var actorMsgSenderComp = Game.Scene.GetComponent<ActorMessageSenderComponent>();
            foreach (var player in players) {
                if (player.IsDisconnect || (excludePlayerId.HasValue && excludePlayerId.Value == player.Id)) {
                    continue;
                }

                var actorMsgSender = actorMsgSenderComp.Get(player.GateClientActorId);
                actorMsgSender.Send(message);
            }
        }

        static System.Diagnostics.Stopwatch frameTimer = new System.Diagnostics.Stopwatch();
        /// <summary>
        /// 在map服务器,给指定几个玩家广播消息
        /// </summary>
        /// <param name="message"></param>
        /// <param name="players"></param>
        public static void MapBroadcastTo(this IActorMessage message, IEnumerable<MapPlayer> players) {
            if (!StartConfigComponent.Instance.StartConfig.AppType.HasFlag(AppType.Map)) {
                Log.Error("必须在Map服务器调用");
                return;
            }
            if (players == null || players.Count() <= 0) return;
            var actorMsgSenderComp = Game.Scene.GetComponent<ActorMessageSenderComponent>();
            foreach (var player in players) {
                if (player.IsDisconnect) {
                    continue;
                }

                var actorMsgSender = actorMsgSenderComp.Get(player.GateClientActorId);

                //frameTimer.Restart();
                actorMsgSender.Send(message);
                /*
                frameTimer.Stop();
                var useMs = (int)frameTimer.ElapsedMilliseconds;
                if (useMs > 10) {
                    Log.Warning("发送单个消息时间超过10毫秒:" + useMs);
                }
                */
            }
        }

        /// <summary>
        /// 在map服务器,发送消息给指定玩家
        /// </summary>
        /// <param name="message"></param>
        /// <param name="player"></param>
        public static void MapSendTo(this IActorMessage message, MapPlayer player) {
            if (!StartConfigComponent.Instance.StartConfig.AppType.HasFlag(AppType.Map)) {
                Log.Error("必须在Map服务器调用");
                return;
            }
            if (player == null) return;
            var actorMsgSenderComp = Game.Scene.GetComponent<ActorMessageSenderComponent>();
            var actorMsgSender = actorMsgSenderComp.Get(player.GateClientActorId);
            actorMsgSender.Send(message);
        }
        #endregion

        #region session的拓展
        /// <summary>
        /// 异步断开连接,如果断开前有消息会发完,需要设置msTime参数,默认500毫秒
        /// </summary>
        /// <param name="session"></param>
        /// <param name="msTime">等待多久后断开</param>
        public static void Disconnect(this Session session, long msTime = 500) {
            DisconnectAsync(session, msTime).Coroutine();
        }
        /// <summary>
        /// 异步断开连接,如果断开前有消息会发完,需要设置msTime参数,默认500毫秒
        /// </summary>
        /// <param name="session"></param>
        /// <param name="msTime">等待多久后断开</param>
        private async static ETVoid DisconnectAsync(this Session session, long msTime = 500) {
            var sessionInsId = session.InstanceId;
            await Game.Scene.GetComponent<TimerComponent>().WaitAsync(msTime);
            if (sessionInsId == session.InstanceId && !session.IsDisposed) {
                session.Dispose();
            }
        }
        #endregion

        #region 在观众服务器发消息
        /// <summary>
        /// 在观众服务器发送消息给观众列表
        /// </summary>
        /// <param name="message"></param>
        /// <param name="auds"></param>
        public static void AudBroadcastTo(this IMessage message, IEnumerable<AudClient> auds) {
            if (!StartConfigComponent.Instance.StartConfig.AppType.HasFlag(AppType.MapAudience)) {
                Log.Error("必须在Aud服务器调用");
                return;
            }
            if (auds == null || auds.Count() <= 0) return;
            var actorMsgSenderComp = Game.Scene.GetComponent<ActorMessageSenderComponent>();
            foreach (var aud in auds) {
                if (aud.IsDisposed) {
                    continue;
                }
                var audClientSession = aud.Parent as Session;
                if (audClientSession == null) {
                    continue;
                }
                audClientSession.Send(message);
            }
        }


        /// <summary>
        /// 在观众服务器发送消息给观众
        /// </summary>
        /// <param name="message"></param>
        /// <param name="aud"></param>
        public static void AudSendTo(this IMessage message, AudClient aud) {
            if (!StartConfigComponent.Instance.StartConfig.AppType.HasFlag(AppType.MapAudience)) {
                Log.Error("必须在Aud服务器调用");
                return;
            }
            if (aud.IsDisposed) {
                return;
            }
            var audClientSession = aud.Parent as Session;
            if (audClientSession == null) {
                return;
            }
            audClientSession.Send(message);
        }
        #endregion
    }

}
